﻿using System;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
//using BaMusaSoft.NumToWords;
using Microsoft.Office.Interop.Word;
using WordApplication = Microsoft.Office.Interop.Word.Application;
using System.Threading;
using System.Collections.Generic;
using BaMusaSoft.RPS.DataModel;
using ThreadingTasks = System.Threading.Tasks;
using System.Windows.Forms;

namespace BaMusaSoft.RPS.RPSServices
{

    /// <summary>
    /// Give me the schedule to be printed and forget about it. if I can print I will print it otherwise I will let you know.
    /// </summary>
    public static class PrintingScheduleService
    {
        static PrintingScheduleService()
        {
            ThreadingTasks.Task.Factory.StartNew(Consume);
        }
        static WordApplication wordApp;
        static readonly object _locker = new object();
        static Queue<Tuple<Schedule, string>> printingJob = new Queue<Tuple<Schedule, string>>();
        static volatile bool printingFinished = false;
        static int sumOfAmountDue;

        /// <summary>
        /// Print schedule in word template.
        /// </summary>
        /// <exception cref="NotSupportedException"></exception>
        /// <exception cref="NullReferenceException"></exception>
        /// <exception cref="FormatException"></exception>
        /// <exception cref="COMException"></exception>
        static void Consume()
        {
            while (true)    //Keep consuming until told otherwise
            {
                Tuple<Schedule, string> job;
                lock (_locker)
                {
                    while (printingJob.Count == 0) Monitor.Wait(_locker);
                    job = printingJob.Dequeue();

                }
                if (job == null) { printingFinished = true; return; } // This signals out exit.
                StartPrintingInWord(job.Item1, job.Item2);  //Do the job;
            }

        }

        public static void PrintAsync(Tuple<Schedule, string> job)
        {
            ThreadingTasks.Task.Factory.StartNew(() =>
                {
                    lock (_locker)
                    {
                        printingJob.Enqueue(job);
                        Monitor.Pulse(_locker);
                    }
                });
            
        }


        private static void StartPrintingInWord(Schedule schedule, string templatePath)
        {
            if (schedule == null || schedule.ScheduleId == "-1")
            {
                throw new ArgumentNullException("There's nothing to print");
            }
            if (schedule.ScheduleDetails.Count > 12)
            {
                throw new NotSupportedException("Can not print more than 12 ScheduleDetails");
            }

            try
            {
                sumOfAmountDue = SumTotalAmountDue();
                wordApp = CreateWord();
                var doc = wordApp.Documents.Add(templatePath);
                foreach (Field f in doc.Fields)
                {
                    //Console.WriteLine(f.Code.Text);
                    PrintField(f, schedule);
                }
                doc.PrintOut();

                //wordApp.Documents[1].Saved = true;
                //wordApp.Quit();
                wordApp.Documents[doc].Close(WdSaveOptions.wdDoNotSaveChanges);

            }
            catch (COMException ex)
            {
                
               return;
            }
            catch (Exception ex)
            {
                return;
            }

        }

        private static WordApplication CreateWord()
        {
            if (wordApp == null)
            {
                return new WordApplication();
            }
            return wordApp;
        }


        public static void ShutdownService()
        {
            //Necessary check for null ref otherwise runtime binding execption will be thrown.
         if (printingJob.Count > 0)
         {
            lock (_locker)
            {
                printingJob.Enqueue(null);
                Monitor.Pulse(_locker);    
            }
                if (MessageBox.Show("توجد مستندات قيد الطباعة هل تريد الإلغاء", "RPS", MessageBoxButtons.YesNo) == DialogResult.No)
                {
                    while (!printingFinished)
                    {
                        Thread.Sleep(1000);
                    }
               }
            }
            if (wordApp != null)
            {
                if (wordApp.Documents.Count > 0)
                {
                    wordApp.Documents[1].Saved = true;
                }

                wordApp.Quit();
                Marshal.ReleaseComObject(wordApp);

            }
        }
        #region "Printing method"

        private static void PrintField(Field f, Schedule schedule)
        {
            if (f.Code.Text.Contains("ScheduleId"))
            {
                f.Result.Text = schedule.ScheduleId.ToString();
                return;
            }
            if (f.Code.Text.Contains("RegistredDay"))
            {
                f.Result.Text = (Helper.ParseDateString(schedule.RegistredAt)).ToString("dddd", new CultureInfo("ar-SA"));
                return;
            }
            if (f.Code.Text.Contains("RegistredAt"))
            {
                string regDate = Helper.DateMiror(schedule.RegistredAt);
                f.Result.Text = regDate;
                return;
            }
            if (f.Code.Text.Contains("CustomerName"))
            {
                f.Result.Text = schedule.Contract.Customer.Name;
                f.Result.Font.Size = 14.0f;
                f.Result.Font.Bold = 1;
                return;
            }
            if (f.Code.Text.Contains("ContractNo"))
            {
                f.Result.Text = schedule.Contract.ContractNo.ToString();
                return;
            }
            if (f.Code.Text.Contains("PropertyDescription"))
            {
                f.Result.Text = schedule.Contract.Property.Description ;
                return;
            }
            if (f.Code.Text.Contains("Rent"))
            {
                f.Result.Text = schedule.Contract.RentBalance.ToString();
                return;
            }
            if (f.Code.Text.Contains("Deposit"))
            {
                f.Result.Text = schedule.Contract.DepositBalance.ToString();
                return;
            }
            if (f.Code.Text.Contains("Maint"))
            {
                f.Result.Text = schedule.Contract.MaintenanceBalance.ToString();
                return;
            }
            if (f.Code.Text.Contains("Total"))
            {
                f.Result.Text = schedule.Contract.Total.ToString();
                return;
            }
            //************** AmountDue **************//
            if (f.Code.Text.Contains("AmountDue01"))
            {
                if (schedule.ScheduleDetails.Count > 0)
                {

                    f.Result.Text = schedule.ScheduleDetails.ElementAt(0).AmountDue.ToString();
                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("AmountDue02"))
            {
                if (schedule.ScheduleDetails.Count > 1)
                {
                    f.Result.Text = schedule.ScheduleDetails.ElementAt(1).AmountDue.ToString();
                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("AmountDue03"))
            {
                if (schedule.ScheduleDetails.Count > 2)
                {

                    f.Result.Text = schedule.ScheduleDetails.ElementAt(2).AmountDue.ToString();

                }

                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("AmountDue04"))
            {
                if (schedule.ScheduleDetails.Count > 3)
                {

                    f.Result.Text = schedule.ScheduleDetails.ElementAt(3).AmountDue.ToString();

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("AmountDue05"))
            {
                if (schedule.ScheduleDetails.Count > 4)
                {

                    f.Result.Text = schedule.ScheduleDetails.ElementAt(4).AmountDue.ToString();

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("AmountDue06"))
            {
                if (schedule.ScheduleDetails.Count > 5)
                {

                    f.Result.Text = schedule.ScheduleDetails.ElementAt(5).AmountDue.ToString();

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("AmountDue07"))
            {
                if (schedule.ScheduleDetails.Count > 6)
                {

                    f.Result.Text = schedule.ScheduleDetails.ElementAt(6).AmountDue.ToString();

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("AmountDue08"))
            {
                if (schedule.ScheduleDetails.Count > 7)
                {

                    f.Result.Text = schedule.ScheduleDetails.ElementAt(7).AmountDue.ToString();

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("AmountDue09"))
            {
                if (schedule.ScheduleDetails.Count > 8)
                {

                    f.Result.Text = schedule.ScheduleDetails.ElementAt(8).AmountDue.ToString();

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("AmountDue10"))
            {
                if (schedule.ScheduleDetails.Count > 9)
                {

                    f.Result.Text = schedule.ScheduleDetails.ElementAt(9).AmountDue.ToString();

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("AmountDue11"))
            {
                if (schedule.ScheduleDetails.Count > 10)
                {

                    f.Result.Text = schedule.ScheduleDetails.ElementAt(10).AmountDue.ToString();

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("AmountDue12"))
            {
                if (schedule.ScheduleDetails.Count > 11)
                {

                    f.Result.Text = schedule.ScheduleDetails.ElementAt(11).AmountDue.ToString();

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            //*****************Date Due ************************************//
            if (f.Code.Text.Contains("DateDue01"))
            {
                if (schedule.ScheduleDetails.Count > 0)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(0).DateDue);

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("DateDue02"))
            {
                if (schedule.ScheduleDetails.Count > 1)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(1).DateDue);

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("DateDue03"))
            {
                if (schedule.ScheduleDetails.Count > 2)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(2).DateDue);

                }

                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("DateDue04"))
            {
                if (schedule.ScheduleDetails.Count > 3)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(3).DateDue);

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("DateDue05"))
            {
                if (schedule.ScheduleDetails.Count > 4)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(4).DateDue);

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("DateDue06"))
            {
                if (schedule.ScheduleDetails.Count > 5)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(5).DateDue);

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("DateDue07"))
            {
                if (schedule.ScheduleDetails.Count > 6)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(6).DateDue);

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("DateDue08"))
            {
                if (schedule.ScheduleDetails.Count > 7)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(7).DateDue);

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("DateDue09"))
            {
                if (schedule.ScheduleDetails.Count > 8)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(8).DateDue);

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("DateDue10"))
            {
                if (schedule.ScheduleDetails.Count > 9)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(9).DateDue);

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("DateDue11"))
            {
                if (schedule.ScheduleDetails.Count > 10)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(10).DateDue);

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }
            if (f.Code.Text.Contains("DateDue12"))
            {
                if (schedule.ScheduleDetails.Count > 11)
                {

                    f.Result.Text = Helper.DateMiror(schedule.ScheduleDetails.ElementAt(11).DateDue);

                }
                else
                {
                    f.Result.Text = null;
                }
                return;
            }

            if (f.Code.Text.Contains("SumOfPayments"))
            {
                f.Result.Text = SumTotalAmountDue().ToString();
                return;
            }
            if (f.Code.Text.Contains("SayInWords"))
            {
                f.Result.Text = "";//SayNumber.ToWords(sumOfAmountDue);
                return;
            }
            if (f.Code.Text.Contains("SignerName"))
            {
                f.Result.Text = schedule.Signer.Name;
                return;
            }
            if (f.Code.Text.Contains("SignerId"))
            {
                f.Result.Text = schedule.Signer.IdNumber;
                return;
            }
            if (f.Code.Text.Contains("IdDate"))
            {
                f.Result.Text = Helper.DateMiror(schedule.Signer.IdDate);
                return;
            }
            if (f.Code.Text.Contains("Mobile"))
            {
                f.Result.Text = schedule.Signer.Mobile;
                return;
            }
            if (f.Code.Text.Contains("FirstPhone"))
            {
                f.Result.Text = schedule.Signer.FirstPhone;
                return;
            }
        }

        private static int SumTotalAmountDue()
        {
            //int n = (from p in schedule.ScheduleDetails
            //         select p.AmountDue).Sum();
            return 0;//n;
        }

        #endregion


    }
}
